// These helpers produce better VM code in JS engines due to their
// explicitness and function inlining.

// 判断一个值是不是undefined或者null
export function isUndef(v){
    return v === undefined || v === null;
}

/**
 * 判断一个值是否被定义过（即不为undefined，不为null）
 * @param {any} v 
 * @returns {Boolean}
 */
export function isDef(v){
    return v !== undefined && v !== null; 
}

// 判断是不是true
export function isTrue(v){
    return v === true;
}

// 判断是不是false
export function isFalse(v){
    return v === false;
}

/**
 * Check if value is primitive.
 */
// 检查值是否为4个基本类型 string,number,symbol,boolean
export function isPrimitive(value){
    return (
        typeof value === 'string' ||
        typeof value === 'number' ||
        // $flow-disable-line
        typeof value === 'symbol' ||
        typeof value === 'boolean'
    )
}

/**
 * Quick object check - this is primarily used to tell
 * Objects from primitive values when we know the value
 * is a JSON-compliant type.
 */
/**
 * 
 * @param {mixed} obj 
 */
 export function isObject (obj) {
    return obj !== null && typeof obj === 'object'
  }

  /**
 * Get the raw type string of a value, e.g., [object Object].
 * __toString用于获取一个数据的原始类型字符串，如 [object Object]
 */
const _toString = Object.prototype.toString

// 返回一个数据的原始类型 如String,Undefined
export function toRawType(value){
    return _toString.call(value).slice(8, -1);
} 

/**
 * Strict object type check. Only returns true
 * for plain JavaScript objects.
 */
// 判断是否是一个普通的对象
export function isPlainObject(obj){
    return _toString.call(obj) === "[Object Object]"
}

// 判断是否是正则表达式
export function isRegExp(v){
    return _toString.call(v) === "[Object RegExp]"
}


/**
 * Check if val is a valid array index.
 */
// 检查val是否是一个有效的数组索引
export function isValidArrayIndex(val){
    const n = parseFloat(String(val));
    return n >= 0 && Math.floor(n) === n && isFinite(val);
}

// 判断是不是一个Promise
export function isPromise(val){
    return (
        isDef(val) &&
        typeof val.then === 'function' &&
        typeof val.catch === 'function'
    )
}

/**
 * Convert a value to a string that is actually rendered.
 */
// 将一个值转换为实际可见的字符串
export function toString(val){
    return val == null
    ?''
    :Array.isArray(val) || (isPlainObject(val) && val.toString === _toString)
    ? JSON.stringify(val, null, 2)
    : String(val);
}

/**
 * Convert an input value to a number for persistence.
 * If the conversion fails, return original string.
 */
// 将输入的值转换为一个数字，如果转换失败，则返回原本的字符
export function toNumber(val){
    const n = parseFloat(val);
    return isNaN(n)?val:n;
}

// 创建一个映射并返回一个函数来检查键是否在该映射中。
/**
 * Make a map and return a function for checking if a key
 * is in that map.
 */
export function makeMap(str,expectsLowerCase){
    const map = Object.create(null);
    const list = str.split(',');
    for (let i = 0; i < list.length; i++) {
        map[list[i]] = true;
    }
    return expectsLowerCase?val=>map[val.toLowerCase()]:val=>map[val];
}


/**
 * Remove an item from an array.
 */
/**
 * 
 * @param {Array<any>} arr 
 * @param {any} item 
 * @returns 
 */
export function remove (arr, item){
    if (arr.length) {
        const index = arr.indexOf(item)
        if (index > -1) {
            return arr.splice(index, 1)
        }
    }
}

/**
 * Perform no operation.
 * Stubbing args to make Flow happy without leaving useless transpiled code
 * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/).
 */

// 一个空函数，可以当做回调函数传入，从而不执行任何操作
export function noop (a,b,c){}
  